Global styles: stop sanitize keeping breakpoints set on an element - #81312
Draft
ramonjd wants to merge 1 commit into
Draft
Global styles: stop sanitize keeping breakpoints set on an element#81312ramonjd wants to merge 1 commit into
ramonjd wants to merge 1 commit into
Conversation
This was referenced Aug 7, 2026
`sanitize()` added a breakpoint state to every element, so an element could carry `@mobile` or `@tablet` directly, at the top level and inside a block. Nothing reads that shape. The target structures are listed four lines above the loop, and the responsive one puts the breakpoint on the block with `elements` inside it. The data survived as far as the database and the REST API, since `remove_insecure_properties()` uses the same schema, while never producing a rule. Drop the loop. CSS output is unchanged, which the existing rendering tests cover, and the two structures that do work are assembled elsewhere from this same element schema. Two sanitization tests now assert the breakpoints are stripped rather than kept, at block and top level.
ramonjd
force-pushed
the
fix/theme-json-sanitize-element-breakpoints
branch
from
August 7, 2026 06:33
2ead2d8 to
60bc9ca
Compare
ramonjd
commented
Aug 7, 2026
| * @covers WP_Theme_JSON_Gutenberg::remove_insecure_properties | ||
| */ | ||
| public function test_remove_insecure_properties_preserves_responsive_block_element_styles() { | ||
| public function test_remove_insecure_properties_strips_breakpoints_set_on_a_block_element() { |
Member
Author
There was a problem hiding this comment.
This inverts an existing assertion. test_remove_insecure_properties_preserves_responsive_block_element_styles asserted the element-nested breakpoints were kept.
Is this change right or is the original correct?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What?
Low priority, data hygiene only. CSS output does not change.
sanitize()adds a breakpoint state to every element, so an element can carry@mobileor@tabletdirectly:{ "version": 3, "styles": { "elements": { "link": { "color": { "text": "black" }, "@mobile": { "color": { "text": "orange" } } } }, "blocks": { "core/group": { "elements": { "link": { "color": { "text": "blue" }, "@mobile": { "color": { "text": "green" } } } }, "@mobile": { "elements": { "link": { "color": { "text": "red" } } } } } } } }Orange and green are kept by the sanitizer and never rendered. Only red produces a media query, which is correct and stays that way.
Why?
The target structures are listed at
lib/class-wp-theme-json-gutenberg.php:1277-1279, four lines above the loop this PR removes:A responsive element is a block breakpoint containing
elements. An element carrying its own breakpoint is not one of the three, and node discovery never looks for it.Because
remove_insecure_properties()builds the same schema, the shape also survives untrusted input, so it can reach the database through user global styles and come back out of the REST API, while producing nothing.The loop is not load-bearing for the shape that does work:
blocks.<block>["@mobile"].elementsis assembled at:1320from the same element schema and does not need breakpoints nested inside each element.How?
Delete the loop, leaving a comment in its place explaining where responsive elements are actually assembled.
Testing Instructions
Use this theme.json
{ "$schema": "../../schemas/json/theme.json", "version": 3, "styles": { "elements": { "link": { "color": { "text": "#0000ff" }, ":hover": { "color": { "text": "#000088" } }, "@mobile": { "color": { "text": "#ff9900" } } } }, "blocks": { "core/group": { "elements": { "link": { "color": { "text": "#008800" }, "@mobile": { "color": { "text": "#ff9900" } } } }, "@mobile": { "elements": { "link": { "color": { "text": "#ff0000" } } } } }, "core/button": { ":hover": { "color": { "background": "#333333" } }, "@mobile": { ":hover": { "color": { "background": "#666666" } } } } } } }Both #ff9900 declarations are the dead shapes and they should be marked "invalid" by the local schema. The CSS shouldn't appear, but they're included just to make sure!
Here's some example HTML
Check:
Kapture.2026-08-07.at.16.46.06.mp4
Related
#81253 makes the schema reject the same two paths, so the editor flags them while typing.